<?php
/*
 * form.class.php
 *
 * Copyright 2011 Szontágh Ferenc <szontagh.ferenc@exahost.eu>
 *
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA 02110-1301, USA.
 */
/**
 * Validate HTML forms, depend on form.class.php
 * @author    Ferenc Szontágh <szontagh.ferenc@exahost.eu>
 */
class validate
{
    /**
     * @var array    get all posts
     */
    private $post = array();
    /**
     * @var array    get all get requets
     */
    private $get = array();
    /**
     * @var object    form container object
     */
    private $forms;
    /**
     * @var array    form attributes for validating
     */
    private $validation = array();
    /**
     * @var bool    fill the forms after send
     */
    public $opt_autofill = true;
    /**
     * @var string    css class for the required inputs, after validating if the input is empty
     */
    public $opt_required_class = 'required';
    /**
     * @var string    class name for the 'p' tag, if validate is fail
     */
    public $opt_error_class = 'error';
    /**
     * error message for the minimum length
     */
    const ERR_MINLENGTH = 'Minimum hossz: ';
    var $err_minlength = "Minimum hossz: ";
    /**
     * error message for the maxlength attr.
     */
    const ERR_MAXLENGTH = 'Maximum hossz: ';
    var $err_maxlength = "Maximum hossz: ";
    /**
     * error message, if the input field is required, but the user leave empty
     */
    const ERR_REQUIRED = 'Kérem ne hagyja üresen a mezőt!';
    var $err_required = "Kérem ne hagyja üresen a mezőt!";
    /**
     * only numbers
     */
    const REGEX_INT = '/^[0-9]+$/';
    /**
     * error message for the numbers
     */
    const ERROR_INT = 'Csak számok!';
    var $err_int = "Csak számok!";
    /**
     * error message for the captcha //TODO: no captcha?
     */
    const REGEX_CAPTCHA = '/(\w|\d)+/';
    var $err_captcha = "Csak számok és betük!";
    /**
     * regex for username
     */
    const REGEX_USERNAME = '/^[A-Za-z][\w]+/i';
    /**
     * regex_username error message
     */
    const ERROR_USERNAME = 'Hibás %s formátum: csak az ábécé betüi, és aláhúzás!';
    var $err_username = "Hibás %s formátum: csak az ábécé betüi, és aláhúzás!";
    /**
     * only letters
     */
    const REGEX_PSTRING = '/^[A-ZÁÉÍÓÖŐÚÜŰa-záéíóöőúüűA]+$/';
    /**
     * regex_pstring errormessage
     */
    const ERROR_PSTRING = 'Csak az ábéc betüi!';
    var $err_pstring = "Csak az ábéc betüi!";
    /**
     * realname, format: first_name last_name
     */
    const REGEX_REALNAME = "/^[A-ZÁÉÍÓÖŐÚÜŰ][a-záéíóöőúüűA-ZÁÉÍÓÖŐÚÜŰ '&-]*[A-Za-z]$/";
    /**
     * regex_pstring errormessage
     */
    const ERROR_REALNAME = 'Csak az ábécé betüi és szóköz! Formátum: \'Vezetéknév Keresztnév\'';
    var $err_realname = 'Csak az ábécé betüi és szóköz! Formátum: \'Vezetéknév Keresztnév\'';
    /**
     * hungarian phone number
     */
    const REGEX_PHONE = "/(\d){1,2}\/(\d){6,7}$/";
    const ERROR_PHONE = "Kérem, a következő formában adja meg számát: 30/1234567";
    var $err_phone = "Kérem, a következő formában adja meg számát: 30/1234567";
    /**
     * domain address (domain.com)
     */
    const REGEX_DOMAIN = '/^([a-z][a-z0-9\-^\.]+(\.))+[a-z]{2,6}$/i';
    /**
     * regex_domain error message
     */
    const ERROR_DOMAIN = 'Hibás %s formátum! (domain.hu)';
    var $err_domain = "Hibás %s formátum! (domain.hu)";
    /**
     * email validation
     */
    const REGEX_EMAIL = '/^[_a-z0-9-]+(.[_a-z0-9-]+)*@[a-z0-9-]+(.[a-z0-9-]+)*(.[a-z]{2,3})$/i';
    /**
     * regex_email error message
     */
    const ERROR_EMAIL = 'Kérem valós e-mail címet adjon meg!';
    var $err_email = "Kérem valós e-mail címet adjon meg!";

    function __construct()
    {
        foreach ($_POST as $pk => $pv) {
            $this->post[$pk] = form::__typeConversion(trim($pv));
        }
        foreach ($_GET as $gk => $gv) {
            $this->get[$gk] = form::__typeConversion(trim($gv));
        }
    }

    /**
     * @desc    gather attributes and validating the inputs
     * @param object $obj    the form.class.php object
     */
    public function valid($obj)
    {
        $this->forms = $obj;
        $return = '';
        for ($i = 0; $i < count($this->validation); $i++) {
            if (isset($this->forms->f[$i]['name']) AND $this->forms->f[$i]['type'] != 'submit' AND array_key_exists($this->forms->f[$i]['name'], $this->post)) {
                $ret = $this->__validate($i);
                if ($ret === true) {
                    $this->forms->addAttr($i, 'valid', $ret);
                    $return[] = true;
                } else {
                    $return[] = false;
                }
            }
        }
        if (is_array($return)) {
            foreach ($return as $h) {
                if ($h === false) {
                    return false;
                }
            }
            return true;
        } else {
            return false;
        }
    }

    /**
     * @desc    add one or more attribute for validating
     * @param mixed $id    the identifier of the input field
     * @param mixed $a    key, or it is array, the array will be passed for validate attr.,
     * @param mixed $v    value, if the $a attr is not array
     */
    public function addAttr($id, $a, $v = null)
    {
        if (is_array($a)) {
            if (isset($this->validation[$id])) {
                $this->validation[$id] = array_merge($this->validation[$id], $a);
            } else {
                $this->validation[$id] = $a;
            }
        } else if ($v != null) {
            $this->validation[$id][$a] = $v;
        }
    }

    /**
     * @desc    the main validator for each input
     * @param mixed $i    the identifier of the input
     * @return mixed
     */
    private function __validate($i)
    {
        if (isset($this->forms->f[$i]['maxlength']) AND strlen($this->post[$this->forms->f[$i]['name']]) > $this->forms->f[$i]['maxlength']) {
            $this->forms->f[$i]['error'] = $this->err_maxlength;
        }
        if (isset($this->validation[$i])) {
            if (isset($this->validation[$i]['required']) AND !empty($this->opt_required_class)) {
                if (isset($this->forms->f[$i]['pclass']) AND !empty($this->forms->f[$i]['pclass'])) {
                    $this->forms->f[$i]['pclass'] .= ' ' . $this->opt_required_class;
                } else {
                    $this->forms->f[$i]['pclass'] = $this->opt_required_class;
                }
            }
            if ($this->opt_autofill === true AND isset($this->post[$this->forms->f[$i]['name']])) {
                $this->forms->f[$i]['value'] = $this->post[$this->forms->f[$i]['name']];
            }
            //check length
            if (isset($this->validation[$i]['required']) AND (!isset($this->post[$this->forms->f[$i]['name']]) OR empty($this->post[$this->forms->f[$i]['name']]))) {
                $this->forms->f[$i]['error'] = sprintf($this->err_required, $this->forms->f[$i]['show']);
                $this->forms->f[$i]['pclass'] = $this->opt_error_class;
                return false;
            }
            if (isset($this->validation[$i]['minlength']) AND strlen($this->post[$this->forms->f[$i]['name']]) < $this->validation[$i]['minlength']) {
                $this->forms->f[$i]['error'] = $this->err_minlength . $this->validation[$i]['minlength'];
                $this->forms->f[$i]['pclass'] = $this->opt_error_class;
                return false;
            }
        }
        //check type
        if (isset($this->validation[$i]['type'])) {
            $constants = $this->GetClassConstants('error');
            foreach ($constants as $ck => $cv) {
                list($ctype, $cval) = explode("_", $ck);
                if ($ctype == 'REGEX') {
                    if ($this->validation[$i]['type'] == $cv) {
                        if (preg_match($cv, $this->forms->f[$i]['value'])) {
                            return true;
                        } else {
                            $this->forms->f[$i]['error'] = sprintf($this->call_error_var($cval), str_replace(":", "", strtolower($this->forms->f[$i]['show'])));
                            $this->forms->f[$i]['pclass'] = $this->opt_error_class;
                            return false;
                        }
                    }
                }
            }
        }
        return true;
    }

    private function call_error_var($cv)
    {
        $class_vars = get_object_vars($this);
        foreach ($class_vars as $name => $value) {
            if (strtolower($name) == "err_" . strtolower($cv)) {
                return $value;
            }
        }
    }

    public function replace_error_msg($arr)
    {
        $class_vars = get_object_vars($this);
        foreach ($class_vars as $name => $value) {
            if (isset($arr[strtolower($name)])) {
                $this->{strtolower($name)} = $arr[strtolower($name)];
            }
        }
    }

    public function getAttr($i, $key)
    {
        if (isset($this->forms->f[$i]) AND isset($this->forms->f[$i][$key])) {
            return $this->forms->f[$i][$key];
        } else {
            return null;
        }
    }

    private function GetClassConstants()
    {
        $oClass = new ReflectionClass($this);
        return $oClass->getConstants();
    }

    function __destroy()
    {
        unset($this->get);
        unset($this->post);
        unset($this->forms);
    }
}

?>